package com.lingkang.flychat.ws;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.lingkang.flychat.dto.ResponseResult;
import com.lingkang.flychat.dto.WsMessage;
import com.lingkang.flychat.dto.WsReceiveStauts;
import com.lingkang.flychat.service.RedisService;
import com.lingkang.flychat.service.UserService;
import com.lingkang.flychat.utils.SpringBeanUtils;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.util.concurrent.GlobalEventExecutor;

import java.util.HashMap;
import java.util.Map;

/**
 * 处理消息的handler
 * 在netty中，是用于为websocket专门处理文本的 对象，frames是消息的载体
 */
public class NettyHandler extends SimpleChannelInboundHandler<WebSocketFrame> {
    private static RedisService redisService;
    private static UserService userService;

    static {
        redisService = SpringBeanUtils.getBean(RedisService.class);
        userService = SpringBeanUtils.getBean(UserService.class);
    }

    //用于记录和管理所有客户端的channel
    private static ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    private static Map<String, String> map = new HashMap<>();

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (null != msg && msg instanceof FullHttpRequest) {
            //转化为http请求
            FullHttpRequest request = (FullHttpRequest) msg;
            //拿到请求地址
            String uri = request.uri();
            request.setUri("/app");
            // 建立请求
            super.channelRead(ctx, request);
            int index = uri.indexOf("?");
            if (index == -1) {
                ctx.channel().writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(new ResponseResult(2, "token无效"))));
                ctx.channel().close();
                return;
            }
            String token = uri.substring(index + 1, uri.length());
            Object username = redisService.get(String.format("token:%s", token));
            if (username == null) {
                ctx.channel().writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(new ResponseResult(2, "token无效"))));
                ctx.channel().close();
                return;
            }
            redisService.set(String.format("netty:%s_8081", username), ctx.channel().id().asShortText(), 60 * 60 * 2);
            map.put(username.toString(), ctx.channel().id().asShortText());
            ctx.channel().writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(new ResponseResult(0, "websocket connect success!"))));
        } else {
            // 建立请求
            super.channelRead(ctx, msg);
        }
    }


    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, WebSocketFrame msg) throws Exception {
        if (msg instanceof TextWebSocketFrame) {
            try {
                System.out.println(((TextWebSocketFrame) msg).text());
                WsMessage message = JSONObject.parseObject(((TextWebSocketFrame) msg).text(), WsMessage.class);
                System.out.println("接收到的数据：" + message.toString());
                WsReceiveStauts stauts = new WsReceiveStauts();
                stauts.setStatus(0);
                stauts.setReturnId(message.getId());
                channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(stauts)));
                if (message.getType() == 1) {
                    String channelId = map.get(message.getReceiveUser());
                    if (channelId == null) {
                        userService.sendMessageToFriend(message, 0);
                        System.out.println("接收的用户不在线！");
                    } else {
                        userService.sendMessageToFriend(message, 1);
                        for (Channel channel : clients) {
                            if (channel.id().asShortText().equals(channelId)) {
                                channel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(message)));
                                break;
                            }
                        }
                    }
                }
            } catch (Exception e) {
                System.out.println("接收数据解析错误，抛弃");
                channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(new ResponseResult(0, "数据解析失败"))));
            }

        } /*else if (msg instanceof CloseWebSocketFrame) {
            System.out.println("客户端断开连接");
        }*/
    }

    /**
     * 当客户端连接到服务端后（打开链接）
     * 获取客户端的channel，并且放到channelGroup中去进行管理
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        clients.add(ctx.channel());
    }

    /**
     * 连接断开，触发移除
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
//        System.out.println("客户端断开，他的长id为:" + ctx.channel().id().asLongText());
        System.out.println("客户端断开，他的短id为:" + ctx.channel().id().asShortText());
        clients.remove(ctx.channel());
        for (Map.Entry<String, String> entry : map.entrySet()) {
            if (entry.getValue().equals(ctx.channel().id().asShortText())) {
                map.remove(entry.getKey());
                redisService.delete(String.format("netty:%s_8081", entry.getKey()));
                break;
            }
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println(cause);
        super.exceptionCaught(ctx, cause);
    }
}
